from celery import shared_task
from interface_test_app.views.process import RequestProcess, AssertProcess
from .models import CaseResultModel, CaseModel, CaseSetModel
from auth_app.models import UserModel
from utils.fmt import datetime_now
from copy import deepcopy
import requests
import json
import time

RESULT = {
    'case_id': None,
    'case_status': False,  # 用例状态
    'request': {
        'method': None,
        'url': None,
        'headers': {},
        'params': None,
        'data': None,
        'json': None,
        'error': [],
    },  # 请求信息
    'response': {
        'status': None,
        'headers': {},
        'time': None,
        'text': None
    },  # 响应信息
    'assert': {
        'pass': [],
        'fail': [],
        'error': [],
    },  # 断言信息
}
'''
先判断响应状态，失败流程止步
在判断断言信息，错误流程止步
'''


def set_request_info(req_info, request_data):
    request_data['method'] = req_info['method']
    request_data['url'] = req_info['url']
    request_data['headers'] = req_info['headers']
    request_data['params'] = req_info['params']
    request_data['data'] = req_info['data']
    request_data['json'] = req_info['json']


def set_response_info(response: requests.models.Response, response_data):
    response_data['headers'] = dict(response.headers)
    response_data['status'] = response.status_code
    response_data['time'] = response.elapsed.total_seconds()
    response_data['text'] = response.text


def _sync_exec(case_id, req_info, assert_info):
    result = deepcopy(RESULT)

    result['case_id'] = case_id

    request = RequestProcess(req_info)
    request.sync_req()
    set_request_info(req_info, result['request'])
    if not request.has_err:
        response = request.get_response()
        set_response_info(response, result['response'])
        AssertObject = AssertProcess(assert_info, response)
        AssertObject.exec_assert()
        if not AssertObject.has_err:
            result['assert']['pass'] = AssertObject.get_assert_pass()
            if AssertObject.has_assert_err:
                # 断言失败
                result['assert']['fail'] = AssertObject.get_assert_error()
            else:
                # 断言成功
                result['case_status'] = True
        else:
            # 断言报错
            result['assert']['error'] = AssertObject.get_errs()
    else:
        # 请求失败
        result['request']['error'] = request.get_errs()
    return result


###########################
# case_info = {
#     'case_id': case_id,
#     'req_info': req_info,
#     'assert_info': assert_info,
#     'user_id': user_id
# }
###########################

# 单个用例执行同步执行结果
@shared_task(name='执行用例')
def execute_case(case_info):
    case_id = case_info['case_id']
    user_id = case_info['user_id']
    case_result = _sync_exec(case_id, case_info['req_info'], case_info['assert_info'])
    return case_result


##############################
# set_info = {
#     'set_id':set_id,
#     'case_infos':[case_info,...]
# }
##############################


@shared_task(name='执行用例集')
def execute_case_set(set_info):
    # 按照set中case顺序依次执行
    set_id = set_info['set_id']
    case_infos = set_info['case_infos']

    set_obj = CaseSetModel.objects.get(id=set_id)

    result_obj = CaseResultModel.objects.create(**{
        'set': set_obj,
        'status': 0  # 任务正在执行
    })

    # 更新set object-----------
    set_obj.execute_fin_time = datetime_now()
    set_obj.execute_num = set_obj.execute_num + 1
    set_obj.save()
    # -------------------------

    # 执行用例-----
    t1 = time.time()
    set_result = {'total': 0, 'success': 0, 'fail': 0, 'result': []}
    for case in case_infos:
        case_id, req_info, assert_info = case['case_id'], case['req_info'], case['assert_info']
        case_result = _sync_exec(case_id, req_info, assert_info)
        set_result['result'].append(case_result)
        set_result['total'] += 1
        if case_result['case_status']:
            set_result['success'] += 1
        else:
            set_result['fail'] += 1

    time.sleep(5)  # 模拟同步执行时长...
    t2 = time.time()
    # -------------

    # 用例执行完毕后，更新result object--------
    result_obj.status = 1
    result_obj.case_num = set_result['total']
    result_obj.success_num = set_result['success']
    result_obj.fail_num = set_result['fail']
    result_obj.time_cost = round((t2 - t1), 2)
    result_obj.result = json.dumps(set_result, ensure_ascii=False, separators=(',', ':'))
    result_obj.save()
    # --------------------------------------
